﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
using xycn.framework.midware;
using xycn.framework.MidwareManagement;
using xycn.pluginsupport.BaseHelperPlugins;

namespace xycn.framework
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        private string baseRoute = "";

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            LogHelper.Info("Step 8:���ÿ�����ԣ��������...",
                       Program.isDebugMode);

            services.AddCors(options =>
            {
                options.AddPolicy("CorsPlolcy",
                    builder =>
                    {
                        if (FrameworkConfig.allowAnyOrigin)
                            builder.AllowAnyOrigin();
                        else
                            builder.WithOrigins(FrameworkConfig.allowOrigins.ToArray());

                        if (FrameworkConfig.allowAnyMethod)
                            builder.AllowAnyMethod();
                        else
                            builder.WithMethods(FrameworkConfig.allowMethods.ToArray());

                        if (FrameworkConfig.allowAnyHeader)
                            builder.AllowAnyHeader();
                        else
                            builder.WithHeaders(FrameworkConfig.allowMethods.ToArray());

                        if (FrameworkConfig.allowCredentials)
                            builder.AllowCredentials();
                        else
                            builder.DisallowCredentials();
                    });
            });

            services.AddControllers();

            LogHelper.Info("Step 8 OK:�����������",
                       Program.isDebugMode);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //���ؿ������
            app.UseCors("CorsPlolcy");

            //ƴ��·�ɻ���ַ
            baseRoute = "/" + FrameworkConfig.basePath + "/" + FrameworkConfig.apiVersion;
            //ѭ��ȥ�����ַ�п��ܴ��ڵ�"//"
            for (; ; )
            {
                if (baseRoute.IndexOf("//") < 0)
                    break;
                baseRoute = baseRoute.Replace("//", "/");
            }
            //����·�ɻ���ַ
            app.UsePathBase(new PathString(baseRoute));

            //�ر�http����ǿ����ת��https
            //app.UseHttpsRedirection();

            app.UseRouting();

            //����Ȩ���м��
            app.UseXlAuthorize();

            //�����м�����
            foreach (MidwareInfo midware in FrameworkConfig.midwareInfos)
            {
                foreach (MidwareMethodInfo method_info in midware.methodInfors)
                {
                    MidwarePluginCaller midwarePluginCaller =
                        new MidwarePluginCaller(midware, method_info);

                    midwarePluginCaller.UserMidwarePlugin(app);
                }
            }

            app.UseEndpoints(RouteConfigure);
        }
        
        /// <summary>
        /// ·������
        /// </summary>
        /// <param name="route"></param>
        private void RouteConfigure(IEndpointRouteBuilder route)
        {
            LogHelper.Info("Step 9:ӳ��Controller·��......",
                       Program.isDebugMode);

            if (ControllerManagement.ControllerManager.controllerInvokers == null)
            {
                LogHelper.Warn("δ�����κ�Controller",
                       Program.isDebugMode);
            }
            else
            {
                //ӳ��·��
                foreach (ControllerManagement.ControllerInvoker invoker in
                    ControllerManagement.ControllerManager.controllerInvokers)
                {
                    if (invoker == null)
                        continue;

                    CreateRouteMap(route, invoker);
                }
            }

            LogHelper.Info("Step 9 OK:Controller·��ӳ�����",
                       Program.isDebugMode);

            LogHelper.Info("****************��������� * ***************\r\n",
                       Program.isDebugMode);
        }
        
        /// <summary>
        /// �������ÿ�������·��ӳ��
        /// </summary>
        /// <param name="invoker"></param>
        private void CreateRouteMap(IEndpointRouteBuilder route,
            ControllerManagement.ControllerInvoker invoker)
        {
            foreach (pluginsupport.ControllerPlugins.Route route_obj in invoker.routeAttrs)
            {
                LogHelper.Info($"WebAPI URI: {(invoker.IsAuth ? "[Auth] " : "")} {invoker.httpMethodType} " + baseRoute + route_obj.mapRoute,
                    Program.isDebugMode);
                switch (invoker.httpMethodType)
                {
                    case pluginsupport.ControllerPlugins.HttpMethodType.DELETE:
                        route.MapDelete(route_obj.mapRoute, invoker.dynamicCaller);
                        break;
                    case pluginsupport.ControllerPlugins.HttpMethodType.GET:
                        route.MapGet(route_obj.mapRoute, invoker.dynamicCaller);
                        break;
                    case pluginsupport.ControllerPlugins.HttpMethodType.POST:
                        route.MapPost(route_obj.mapRoute, invoker.dynamicCaller);
                        break;
                    case pluginsupport.ControllerPlugins.HttpMethodType.PUT:
                        route.MapPut(route_obj.mapRoute, invoker.dynamicCaller);
                        break;
                }
            }
        }

        /// <summary>
        /// �м��������
        /// </summary>
        class MidwarePluginCaller
        {
            private object midwareObject = null;
            public MidwareMethodInfo midwareMethodInfo = null;

            public MidwarePluginCaller(MidwareInfo midware_info,
                MidwareMethodInfo method_info)
            {
                if (midware_info == null || method_info == null)
                    return;

                midwareObject = Activator.CreateInstance(midware_info.midwareType);
                midwareMethodInfo = method_info;
            }

            /// <summary>
            /// �м������
            /// </summary>
            /// <param name="context"></param>
            /// <param name="task"></param>
            /// <returns></returns>
            private async Task MidwareMethod(HttpContext context, Func<Task> task)
            {
                if (midwareMethodInfo != null)
                {
                    object[] parameters = new object[2];
                    parameters[0] = context;
                    parameters[1] = task;

                    var midware_task =
                        midwareMethodInfo.methodInfor.Invoke(midwareObject, parameters)
                        as Task;
                    await midware_task;
                }
            }

            /// <summary>
            /// �����м�����
            /// </summary>
            public void UserMidwarePlugin(IApplicationBuilder app)
            {
                app.Use(this.MidwareMethod);
            }
        }
    }
}
